package A3D_Test 
{
	import A3D_Test.ModelInstance;
	import A3D_Test.ModelResource;
	import alternativa.engine3d.core.Camera3D;
	import alternativa.engine3d.core.Object3D;
	import alternativa.engine3d.core.View;
	import flash.display.InteractiveObject;
	import flash.display3D.Context3D;
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.geom.Matrix3D;
	import flash.geom.Vector3D;
	import flash.ui.Keyboard;

	public class LocalClient extends Object3D
	{
		public function LocalClient( ctx:Context3D, eventSource:InteractiveObject, frameRate:Number )
		{
			frameTime = 1.0 / frameRate;

			var hullRes:ModelResource = new ModelResource( ctx, "myviper.dae" );
			
			hullModel = new ModelInstance( hullRes );
			addChild( hullModel );

			initCamera( ctx );
			initKeys( eventSource );
			
			eventSource.addEventListener( Event.ENTER_FRAME, onEnterFrame );
		}
		
		public function get camera():Camera3D {
			return cam;
		}
		
		
		private function initCamera( ctx:Context3D ):void
		{
			cam = new Camera3D( 0.1, 1000.0 );
			cam.view = new View( 1024, 768 );
			
			//We want align camera along X axis
			//We CANNOT modify matrix directly through 'matrix' property, we have to get then set in manually
			var M:Matrix3D = cam.matrix.clone();
			M.appendRotation( -90.0, new Vector3D( 0, 0, 1 ) );
			M.appendRotation( 90.0, new Vector3D( 0, 1, 0 ) );
			M.appendTranslation( -10, 0, 3 );
			cam.matrix = M;
			
			addChild( cam );
		}
		
		
		
		private function initKeys( eventSource:InteractiveObject ):void
		{
			eventSource.addEventListener( KeyboardEvent.KEY_DOWN, onKeyDown );
			eventSource.addEventListener( KeyboardEvent.KEY_UP, onKeyUp );
		}
		
		
		private function onKeyDown( e:KeyboardEvent ):void
		{
			if ( e.keyCode == Keyboard.W ) keyStateUp = true;
			if ( e.keyCode == Keyboard.S ) keyStateDown = true;
			if ( e.keyCode == Keyboard.A ) keyStateLeft = true;
			if ( e.keyCode == Keyboard.D ) keyStateRight = true;
			keyStateFwd = e.shiftKey;
			if ( e.keyCode == Keyboard.SPACE ) keyStateBack = true;
		}
		
		
		private function onKeyUp( e:KeyboardEvent ):void
		{
			if ( e.keyCode == Keyboard.W ) keyStateUp = false;
			if ( e.keyCode == Keyboard.S ) keyStateDown = false;
			if ( e.keyCode == Keyboard.A ) keyStateLeft = false;
			if ( e.keyCode == Keyboard.D ) keyStateRight = false;
			keyStateFwd = e.shiftKey;
			if ( e.keyCode == Keyboard.SPACE ) keyStateBack = false;
		}


		public function onEnterFrame( e:Event ):void
		{
			var dt:Number = frameTime;

			currentLinearSpeed = doScalarKeys( currentLinearSpeed, maxLinearSpeed, linearAccel, dt, keyStateFwd, keyStateBack );
			currentPitchSpeed = doScalarKeys( currentPitchSpeed, maxAngularSpeed, angularAccel, dt, keyStateUp,  keyStateDown );
			currentRollSpeed = doScalarKeys( currentRollSpeed, maxAngularSpeed, angularAccel, dt, keyStateRight, keyStateLeft );
			
			var M:Matrix3D = matrix.clone();

			M.prependTranslation( currentLinearSpeed * dt, 0, 0 );
			M.prependRotation( currentPitchSpeed, new Vector3D( 0, 1, 0 ) );
			M.prependRotation( currentRollSpeed, new Vector3D( 1, 0, 0 ) );

			matrix = M;
		}
		
		
		private function doScalarKeys( speed:Number, speedLimit:Number, accel:Number, dt:Number, incKey:Boolean, decKey:Boolean ):Number
		{
			var result:Number = speed;
			
			var dspeed:Number = dt * accel;
			if ( incKey && !decKey )
				result += dspeed * ( result < 0 ? 2.0 : 1.0 );
			else if ( decKey && !incKey )
				result -= dspeed * ( result > 0 ? 2.0 : 1.0 );
			else
			{
				if ( result < -dspeed )
					result += dspeed;
				else if ( result > +dspeed )
					result -= dspeed;
				else
					result = 0;
			}
			
			if ( result > speedLimit )
				result = speedLimit;
			else if ( result < -speedLimit )
				result = -speedLimit;
			
			return result;
		}
		
		private var hullModel:ModelInstance;
		private var cam:Camera3D;
		private var frameTime:Number;
		
		private var keyStateUp:Boolean = false;
		private var keyStateDown:Boolean = false;
		private var keyStateLeft:Boolean = false;
		private var keyStateRight:Boolean = false;
		private var keyStateFwd:Boolean = false;
		private var keyStateBack:Boolean = false;
		
		private var currentLinearSpeed:Number = 0.0;
		private var currentPitchSpeed:Number = 0.0;
		private var currentRollSpeed:Number = 0.0;
		
		private var maxLinearSpeed:Number = 30.0;
		private var linearAccel:Number = 7.5;
		private var maxAngularSpeed:Number = 1.0 * Math.PI;
		private var angularAccel:Number = 0.75 * Math.PI;
	}
}
